//类的功能：束腰式实例属性、原型属性、静态属性、访问器
//-----------------1、类的实例属性----------------------------
//类：类本身可以充当类型，可以描述实例（类类型）
const str: String = "444"; //String就是一个类
//ts中所有的属性要求必须先申明再使用（采用修饰符来申明）
class Circle {
  public name: string;
  public age: number;
  constructor(name: string, age?: number) {
    this.name = name;
    this.age = age || 100;
  }
}
const circle = new Circle("tom", 18);
console.log(4551, circle);
//以下4个是类的修饰符
//public：公开的属性（父、子、外界都可以访问），不写默认就是public
//protected受保护的（父、子可以访问），外界不能访问
//private （父），在子和外部都不能访问
//readonly 仅读属性 ，只能赋初始值，后续不可更改

class Animal {
    #xxx='abc' //私有属性，js es新语法，在外界不管什么方法都不能访问
  //接受完再赋值，和上面的写法一样
  constructor(public name: string, private sex: 0 | 1,protected color:string, public age: number,readonly abc?:string) {
    this.name = name;
    this.age = age || 100;
    this.sex = sex;
    this.color=color;
    this.abc=abc
  }
}

class Cat extends Animal {
  constructor(name: string, sex: 0 | 1, color:string,age: number,abc:string) {
    super(name, sex,color,age,abc);
    console.log(this.color); // color:受保护的（protected），父和子可以访问
    //this.abc='233'//abc是只读属性，不能修改
    console.log(this.abc);
    
    
  }
}
const cat = new Cat("Tom猫", 0, 'pink',18,'abc');
console.log(100, cat, cat.name);

//console.log(100,cat,cat.sex); //sex 为私有属性（private）只能在父里面访问
//console.log(100, cat, cat.color);color:受保护的（protected），父和子可以访问，外界不能访问
console.log(101,cat,cat['sex'])//使用此方法可以访问私有属性（protected、private），绕过ts检测，不建议这么使用
console.log(102,cat,cat['color'])//使用此方法可以访问私有属性（protected、private），绕过ts检测，不建议这么使用
//console.log(102,cat,cat['#xxx']) //#开头的命令，是私有属性，无论什么方法都不能访问

//-----------------2、类的访问器(属性访问器)----------------------------

class Animal2{
    private _sound:string='';
    static habitat='地球'
    static getHabitat(){
        return this.habitat
    }
    constructor(){

    }
    get sound(){
        return this._sound
    }
    set sound(val:string){
        this._sound=val
    }
    eat(val:string){
        return `正在吃${val}`
    }
}
class Cat2 extends Animal2{
    constructor(){

        super()
    }
    static getHabitat(){
        //super，静态方法中访问指向父类
        return super.getHabitat()
    }
    //重写父类（Animal2）的eat方法，参数要么不传，传类型必须一致
    eat(){
        return 'ddd'
    }
   
}
const animalCat2=new Cat2()
animalCat2.sound='毛毛虫'
console.log(2000,animalCat2.sound);

//-----------------3、原型方法----------------------------
//具体实现看上面的eat方法
console.log(3000,animalCat2.eat());

//-----------------4、静态方法----------------------------
//静态方法,可以被子勒继承，参考上面的getHabitat
console.log(4000,Cat2.getHabitat());

//-----------------5、super:原型方法指向实例，构造函数和静态方法指向父类----------------------------
//参考animalCat2

//-----------------6.抽象(private)----------------------------
//1.给构造函数添加抽象
class SingleTon1{
    private constructor(){ //给constructor添加private之后,SingleTon就不能被new

    }
}
//new SingleTon1()//SingleTon就不能被new，这种使用场景可以运用到单例模式

class SingleTon{
    private static instance=new SingleTon()
    private constructor(){ //给constructor添加private之后,SingleTon就不能被new

    }
    static getInstance(){
        return this.instance
    }
}
const s1=SingleTon.getInstance()
const s2=SingleTon.getInstance()
console.log(6000,s1===s2);//true

//抽象类
//1、不能被new
//2、抽象类中，可以创建属性和方法被子类继承，但是静态方法不可以
abstract class Animal6{
    static habitat='地球'
    abstract eat():void;//没有具体实现，一般描述原型方法
    abstract play:()=>void;//没有具体实现，ts中不做区分，但是一般描述的是实例方法
    //默认采用eat()来申明
    drink(){

    }
}
class Cat6 extends Animal6{
    eat(): void {
        throw new Error("Method not implemented.");
    }
    play!: () => void;
    //    play: () => void=()=>{}; 这样写就可以被new访问
    
}
let cat6=new Cat6();
console.log(60001,cat6);

export {};
